package com.googlecode.chigs.repository.jpa.impl;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.mail.internet.MimeMessage;

import org.apache.velocity.app.VelocityEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.security.providers.dao.SaltSource;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.velocity.VelocityEngineUtils;

import com.googlecode.chigs.domain.User;
import com.googlecode.chigs.domain.UserSettings;
import com.googlecode.chigs.repository.UserService;
import com.googlecode.chigs.repository.jpa.UserDao;
import com.googlecode.chigs.repository.jpa.UserSettingsDao;

@Service(value="userService")
@Transactional
public class UserDetailsServiceImpl implements UserService, UserDetailsService {
	private final static Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private SaltSource saltSource;
	
	@Autowired
	private JavaMailSender mailSender;

	@Autowired
	private VelocityEngine velocityEngine;

	@Resource
	private UserDao userDao;
	
	@Resource
	private UserSettingsDao userSettingsDao;

    private static int randomInt(int min, int max) {
        return (int)(Math.random() * (max - min) + min);
    }
    
    private static String randomString(int min, int max) {
        int num = randomInt(min, max);
        byte b[] = new byte[num];
        for (int i = 0; i < num; i++) {
            b[i] = (byte)randomInt('a', 'z');
        }
        return new String(b);
    }

    public void initAdmin() {
		if (userDao.count().longValue() == 0) {
			User admin = new User();
			admin.setEmail("admin@localhost");
			admin.setPassword("admin");
			admin.setFirstname("auto");
			admin.setLastname("generated");
			admin.setAdmin(true);
			admin.setEnabled(true);
			saveUser(admin);
			log.info("auto generated admin user created. Login: admin@localhost / Password: admin");
		}
	}
	
	@Override
	public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException, DataAccessException {
		final User user = userDao.findByEmail(email);
		if (user == null) {
			throw new UsernameNotFoundException("no user for email: " + email);
		}
		return new UserServiceImpl(user);
	}

	@Override
	public User saveUser(User user) {
		if (user.isNew()) {
			UserSettings settings = new UserSettings();
			userSettingsDao.save(settings);
			user.setUserSettings(settings);
			user = userDao.save(user);
			user.setPassword(passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(new UserServiceImpl(user))));
			user.setActivationKey(randomString(10, 12));
		} else {
			final User u = userDao.findByEmail(user.getEmail());
			if (user.getPassword() == null || "".equals(user.getPassword())) {
				user.setPassword(u.getPassword());
			} else {
				user.setPassword(passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(new UserServiceImpl(user))));
			}
		}
		return userDao.save(user);
	}

	@Override
	public void deleteUser(User user) {
		userDao.delete(userDao.readByPrimaryKey(user.getId()));
	}
	
	@Override
	public void signupUser(User user) {
		final User u = saveUser(user);

		MimeMessagePreparator preparator = new MimeMessagePreparator() {
			public void prepare(MimeMessage mimeMessage) throws Exception {
	            MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
	            message.setTo(u.getEmail());
	            message.setFrom("webmaster@chigs.googlecode.com"); // could be parameterized...
	            message.setSubject("Account activation change configs");
				Map<String, User> model = new HashMap<String, User>();
				model.put("user", u);
				String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "com/googlecode/chigs/repository/signup.vm", model);
	            message.setText(text, true);
	            log.info(message.getMimeMessage().toString());
			}
		};
		try {
			this.mailSender.send(preparator);
		} catch (MailException ex) {
			log.error("error sending activation mail. user will be enabled automatically.", ex);
			u.setEnabled(true);
			userDao.save(u);
		}
	}
}
